import pandas as pd
from hpelm import ELM
from sklearn.preprocessing import MinMaxScaler
from pylab import *
import numpy
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

def mean_absolute_percentage_error(y_true, y_pred):
    y_true, y_pred = np.array(y_true), np.array(y_pred)
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

def transfer_Data(file_name):
    dat = pd.read_csv(file_name)
    x = dat.loc[:, [x for x in dat.columns.tolist() if x not in ('NEE')]].values
    y = np.array(dat.NEE)
    train_size = int(len(dat) * 0.75)
    return x, y, train_size


def scaler_for_data(x, y, scaler_for_x, scaler_for_y):
    x_scaler = scaler_for_x.fit_transform(x)
    y_scaler = scaler_for_y.fit_transform(y.reshape(-1, 1))
    return x_scaler, y_scaler


def inverse_transform(y, scaler_for_y):
    y_true = scaler_for_y.inverse_transform(y.reshape(-1, 1))
    return y_true

def get_r2_numpy(x, y):
    slope, intercept = np.polyfit(x, y, 1)
    r_squared = 1 - (sum((y - (slope * x + intercept)) ** 2) / ((len(y) - 1) * np.var(y, ddof=1)))
    return r_squared

def RMSE(y_true, y_predict):
    return np.sqrt(((y_true - y_predict) ** 2).mean())

def MAE(y_true, y_predict):
    return np.abs((y_true - y_predict)).mean()


def score_R2(ans, y_test):
    pmean = np.mean(y_test)
    omean = np.mean(ans)
    SSR = 0.0
    varp = 0.0
    varo = 0.0
    for i in range(0, len(y_test)):
        diffXXbar = y_test[i] - pmean
        difYYbar = ans[i] - omean
        SSR += (diffXXbar * difYYbar)
        varo += diffXXbar ** 2
        varp += difYYbar ** 2
    SST = math.sqrt(varo * varp)
    return (SSR / SST) ** 2

def score_MAE(ans, y_test):
    return abs((y_test - ans).mean())

scaler_for_x = MinMaxScaler(feature_range=(0, 1))
scaler_for_y = MinMaxScaler(feature_range=(0, 1))
x, y, train_size = transfer_Data("US-Myb_HH_TOTAL.csv")
x_scaler, y_scaler = scaler_for_data(x, y, scaler_for_x, scaler_for_y)
x_train = x_scaler[:train_size, :]
y_train = y_scaler[:train_size]
x_test = x_scaler[train_size:, :]
y_test = y_scaler[train_size:]

elm = ELM(x_train.shape[1], 1)
elm.add_neurons(100, "sigm")
elm.train(x_train, y_train)
predict_test = elm.predict(x_test)
predict_train = elm.predict(x_train)

predict_test = inverse_transform(predict_test, scaler_for_y)
predict_train = inverse_transform(predict_train, scaler_for_y)

train_true = inverse_transform(y_train, scaler_for_y)
test_true = inverse_transform(y_test, scaler_for_y)
# print("true_train:", y[:10])
# print("y_true_train:",train_true[:10])
# print("y_true_test:",test_true[:10])
# print("predict_train:", predict_train[:10])
# print("true_test:", y[train_size:train_size + 10])
# print("predict_test:", predict_test[:10])

train_rmse = RMSE(train_true, predict_train)
test_rmse = RMSE(test_true, predict_test)
print("train_rmse:", train_rmse)
print("test_rmse:", test_rmse)
train_rmse = MAE(train_true, predict_train)
test_rmse = MAE(test_true, predict_test)
print("train_mae:", train_rmse)
print("test_mae:", test_rmse)
train_r2 = score_R2(predict_train,train_true)
test_r2 = score_R2(predict_test,test_true)
print("train_r2:", train_r2)
print("test_r2:", test_r2)

true_list = numpy.array(numpy.concatenate((train_true, test_true)))
pred_list = numpy.array(numpy.concatenate((predict_train, predict_test)))

# print("true_list: " + str(list(true_list.squeeze())))
# print("pred_list: " + str(list(pred_list.squeeze())))

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(range(len(true_list)), true_list, c="black")
ax.plot(range(len(pred_list)), pred_list, c="red")
x_ticks = ax.set_xticks(range(len(true_list) / 24, len(true_list), len(true_list) / 12))
x_labels = ax.set_xticklabels(range(1, 13, 1), fontsize="small")
ax.set_xlabel("Month")
ax.set_ylabel("NEE(gCO2 m-2 d-1)")
ax.legend()
plt.show()